package components.intertitles;

import java.awt.BasicStroke;
import java.awt.Color;
import java.util.ArrayList;

import menus.common.AbstractMenu;
import menus.demm.DEMM;
import menus.flower.FlowerMenu;
import menus.zone.ZoneMenu;

import components.SetupExperiment;

import fr.inria.insitu.noe.Platform;
import fr.inria.insitu.noe.Platform.EndCondition;
import fr.inria.insitu.noe.exp.model.Block;
import fr.inria.insitu.noe.exp.model.Experiment;
import fr.lri.swingstates.canvas.CRectangle;
import fr.lri.swingstates.canvas.CShape;
import fr.lri.swingstates.canvas.Canvas;

/**
 * @author mathieu
 *  
 * @touchstone.intertitle Trial
 *
 */

public class Trial extends Block {
	
	public static final String ExecTime = "ExecutionTime";
	public static final String ReacTime = "ReactionTime";
	
	public static final String OError = "OrientationError";
	public static final String ShapeError = "ShapeError";
	public static final String LengthError = "LengthError";
	public static final String PositionError = "PositionError";
	
	public static final String Training = "Training";
	public static final String Pause = "Pause";
	
	public static final String Px = "Mouse.x";
	public static final String Py = "Mouse.y";
	
	public static final String Technique = "Technique";
	public static final String Capacity = "Capacity";
	public static final String Item = "Item";
	
	public static final String DEMM = "DEMM";
	public static final String Flower = "Flower";
	public static final String Zone = "Zone";
	
	public static final String CurrentMenu = "CurrentMenu";
	
	public static final String UtilTag = "Utils";
	
	protected static final int frameThickness = 50;
	protected CRectangle frame;
	protected static final String FrameTag = "Frame Tag";
	
	protected CRectangle[] progressBar;
	protected static final int BarThickness = 40;
	protected static final int BarGap = 1;
	protected static final String ProgressBarTag = "ProgressBar Tag";
	
	protected static final String PreviousStateMachine = "Previous State Machine";
	
	protected Canvas canvas;
	
	protected static AbstractMenu menu;
	
	protected long trialStartTime;

	public Trial() {
		
		super();
		
		canvas = ((SetupExperiment)Platform.getExperiment().getSetUp()).getGestureArea();
		
		frame = canvas.newRectangle(0, 0, canvas.getWidth(), canvas.getHeight());
		frame.setFilled(false)
			.setOutlinePaint(new Color(100, 255, 100))
			.setStroke(new BasicStroke(frameThickness))
			
			.setPickable(false)
			.setDrawable(false)
			
			.addTag(FrameTag);

	}

	@Override
	public void beginBlock() {
		
		// wtf?
		//Platform.getInstance().setMeasureValue(Training, Platform.getInstance().getFactorValue(Training));
		
		String menuType = Platform.getInstance().getFactorValue(Technique).toString();
		int menuCapacity = new Integer(Platform.getInstance().getFactorValue(Capacity).toString());
		
		String[][] itemLabels; 
		
		// Progress bar
		
		int nbTrials = (Integer)Platform.getInstance().getMeasureValue(Experiment.MEASURE_EXPERIMENT_NB_TRIAL);
		
		progressBar = new CRectangle[nbTrials];
		
		double tickWidth = (TrialInstructions.ZONE_WIDTH - frameThickness) / nbTrials - BarGap;
		
		for (int trial = 0; trial < nbTrials; trial++){
			
			progressBar[trial] = (CRectangle)canvas.newRectangle(
														BarThickness/2 + 20 + trial * (tickWidth + BarGap), 
														canvas.getHeight() - 3 * BarThickness, 
														tickWidth, 
														BarThickness)
													.setOutlined(false)
													.setFilled(true)
													.setFillPaint(Color.white)
													
													.setDrawable(true)
													.setPickable(false)
													
													.addTag(ProgressBarTag);
			
		}
		
		// Menu
		
		if (menuType.equalsIgnoreCase(DEMM)){
			
			itemLabels = new String[menuCapacity/8][8];
			
			menu = new DEMM(canvas, itemLabels);
			
		} 
		else if (menuType.equalsIgnoreCase(Flower)){
			
			switch (menuCapacity) {
			case 16:
				
				itemLabels = new String[][]{
						{"", "", ""},
						{"", ""},
						{"", "", "", ""},
						{""},
						{"", "", ""},
						{""},
						{null, "", ""},
						{}
				};
				
				break;
				
			case 24:
				
				itemLabels = new String[][]{
						{"", "", "", ""},
						{"", "", ""},
						{"", "", "", "", ""},
						{"", ""},
						{"", "", "", ""},
						{"", ""},
						{null, "", "", ""},
						{""}
				};
				
				break;
				
			case 32:
				
				itemLabels = new String[][]{
						{"", "", "", "", ""},
						{"", "", "", ""},
						{"", "", "", "", "", ""},
						{"", "", ""},
						{"", "", "", "", ""},
						{"", "", ""},
						{"", "", "", ""},
						{"", ""}
				};
				
				break;

			default:
				
				System.err.println("ERROR : Illegal capacity " + menuCapacity);
				itemLabels = new String[0][0];
				
				break;
			}
			
			menu = new FlowerMenu(canvas, itemLabels);
			
		}
		else if (menuType.equalsIgnoreCase(Zone)){
			
			if (menuCapacity == 16){
				
				itemLabels = new String[4][4];
				
			}
			else {
				
				itemLabels = new String[menuCapacity / 8][8];
				
			}
			
			menu = new ZoneMenu(canvas, itemLabels);
			
		}
		
		Platform.getInstance().setMeasureValue(CurrentMenu, menu);
		
		frame.setDrawable(Platform.getInstance().getFactorValue(Training).toString().equalsIgnoreCase("yes"));
		
		System.out.println("\n===============================================================================\n");
		System.out.println("\tBLOCK " + Platform.getInstance().getMeasureValue(Experiment.MEASURE_EXPERIMENT_BLOCK).toString());
		System.out.println("\n\tTechnique : " + menuType);
		System.out.println("\tCapacity  : " + menuCapacity);
		System.out.println("\tTraining  : " + Platform.getInstance().getFactorValue(Training).toString());
		
		System.out.println("\n===============================================================================");
		
	}
	
	
	
	public void beginTrial() {
		
		menu.resetSelection();
		
		int targetIndex = new Integer(Platform.getInstance().getFactorValue(Item).toString());
		
		menu.setTargetIndex(targetIndex);
		
		frame.aboveAll();
		
		for (CRectangle tick : progressBar){
			
			//tick.setDrawable(true);
			tick.above(frame);
		}
		
		int currentTrial = (Integer)Platform.getInstance().getMeasureValue(Experiment.MEASURE_EXPERIMENT_TRIAL);
		
		progressBar[currentTrial-1].setFillPaint(Color.green);
		
		((AbstractMenu)Platform.getInstance().getMeasureValue(Trial.CurrentMenu)).drawInstructions(canvas, canvas.getTag(TrialInstructions.ZoneInstructionsTag).firstShape());
		
		trialStartTime = System.currentTimeMillis();

		System.out.println("--------------------------------------------------------------------------------");
		System.out.println("\n\t\tTRIAL " + Platform.getInstance().getMeasureValue(Experiment.MEASURE_EXPERIMENT_TRIAL).toString());
		System.out.println("\t\tItem  : " + targetIndex);
		
	}
	
	@Override
	public void endTrial(EndCondition arg0) {
		
		// WRONG : 
		// The logging method is called before endTrial()
		// setMeasureValues();
		
		System.out.println("\t\tResults :");
		System.out.println("\t\t\t- Reaction Time     : " + (menu.getStartTime() - trialStartTime));
		System.out.println("\t\t\t- Execution Time    : " + menu.getSelectionDuration());
		System.out.println("\t\t\t- Orientation Error : " + menu.getOrientationError());
		System.out.println("\t\t\t- Shape Error       : " + menu.isShapeError());
		System.out.println("\t\t\t- Length Error      : " + menu.getLengthError());
		System.out.println("\t\t\t- Position Error    : " + menu.getPositionError());
		
	}
	
	@Override
	public void endBlock() {
		
		super.endBlock();
		
		menu.stopAllAnimations();
		
		clearTheCanvasExcept(UtilTag);
		
		menu.getStateMachine().suspend();
		menu.getStateMachine().detach(canvas);
		
	}
	
	protected void clearTheCanvasExcept(String... exceptTags){
		
		/*
		 * Problem : canvas.removeAllShapes() throws a NullPointerException. It seems that some of the
		 * CShapes in canvas.getDisplayList() have their canvas attribute null.
		 * So I had to call CShape.remove() for all the shapes in the canvas displayList, but as this
		 * modifies the displayList during the iteration, I had to copy its content in another list.
		 */
		
		ArrayList<Object> leavingShapes = new ArrayList<Object>(canvas.getDisplayList().size());
		
		for (Object o : canvas.getDisplayList()){
			leavingShapes.add(o);
		}
		
		for (String tag : exceptTags){
			if (canvas.getTag(tag) != null)
				for (Object o : canvas.getTag(tag).getCollection()){
					leavingShapes.remove(o);
				}
		}
		
		for (Object s : leavingShapes){
			((CShape)s).remove();
		}
		
		System.out.println("\n\t\tCLEAR : " + leavingShapes.size() + " shapes removed");
		
	}
	
	public void setMeasureValues() {
		
		// DONE get values from the menu itself
		
		menu.setExperimentMeasures();
		
		Platform.getInstance().setMeasureValue(ReacTime, menu.getStartTime() - trialStartTime);
		Platform.getInstance().setMeasureValue(ExecTime, menu.getSelectionDuration());
		
		Platform.getInstance().setMeasureValue(OError, menu.getOrientationError());
		Platform.getInstance().setMeasureValue(ShapeError, menu.isShapeError());
		Platform.getInstance().setMeasureValue(LengthError, menu.getLengthError());
		Platform.getInstance().setMeasureValue(PositionError, menu.getPositionError());
		
	}

}
